/*
* Copyright 2010 Gal Dolber.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.guit.rebind.jsorm;
import com.google.gwt.core.ext.BadPropertyValueException;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JArrayType;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JField;
import com.google.gwt.core.ext.typeinfo.JGenericType;
import com.google.gwt.core.ext.typeinfo.JParameterizedType;
import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONBoolean;
import com.google.gwt.json.client.JSONNull;
import com.google.gwt.json.client.JSONNumber;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.json.client.JSONValue;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
import com.guit.client.jsorm.BooleanSerializer;
import com.guit.client.jsorm.DateSerializer;
import com.guit.client.jsorm.DoubleSerializer;
import com.guit.client.jsorm.FloatSerializer;
import com.guit.client.jsorm.IntegerSerializer;
import com.guit.client.jsorm.LongSerializer;
import com.guit.client.jsorm.StringSerializer;
import com.guit.client.jsorm.TypeJsonSerializer;
import com.guit.client.jsorm.VoidSerializer;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* Json serializer generator. Support virtually any kind of serializable data
* but java.lang.Object. For Iterable Interfaces like java.util.Set,
* java.util.List or java.util.Map you need to add an exception to specify what
* implementation to use. java.util.List, java.util.Set, java.util.Map are
* already supported. See Framework.gwt.xml.
*/
public class JsonSerializerUtil {
private static final JType[] emptyParameter = new JType[]{};
private static final String jsonObject = JSONObject.class.getCanonicalName();
private static TreeLogger logger;
private static HashMap<String, String> exceptions;
private static void error(String message, Object... params) throws UnableToCompleteException {
logger.log(TreeLogger.ERROR, String.format(message, params));
throw new UnableToCompleteException();
}
public static String generate(TreeLogger logger, GeneratorContext context, JClassType pojoType)
throws UnableToCompleteException {
JsonSerializerUtil.logger = logger;
// We cannot serialize java.lang.Object
String pojoQualifiedName = pojoType.getQualifiedSourceName();
if (pojoQualifiedName.equals(Object.class.getCanonicalName())) {
error("You cannot serialize Object... we either");
}
if (exceptions == null) {
exceptions = new HashMap<String, String>();
try {
List<String> ormExceptions =
context.getPropertyOracle().getConfigurationProperty("json.orm.exception").getValues();
for (String e : ormExceptions) {
String[] parts = e.split(" ");
if (parts.length != 2) {
error(
"Bad json orm exception format. i.e 'java.util.List java.util.ArrayList<%s>. Found: %s'",
e);
}
exceptions.put(parts[0], parts[1]);
}
} catch (BadPropertyValueException e) {
throw new IllegalStateException(e);
}
}
String parameterizedQualifiedSourceName = pojoType.getParameterizedQualifiedSourceName();
String typeName = parameterizedQualifiedSourceName;
// Basic types
if (typeName.equals(Void.class.getCanonicalName())) {
return VoidSerializer.class.getCanonicalName();
} else if (typeName.equals(String.class.getCanonicalName())) {
return StringSerializer.class.getCanonicalName();
} else if (typeName.equals(Integer.class.getCanonicalName())) {
return IntegerSerializer.class.getCanonicalName();
} else if (typeName.equals(Long.class.getCanonicalName())) {
return LongSerializer.class.getCanonicalName();
} else if (typeName.equals(Double.class.getCanonicalName())) {
return DoubleSerializer.class.getCanonicalName();
} else if (typeName.equals(Float.class.getCanonicalName())) {
return FloatSerializer.class.getCanonicalName();
} else if (typeName.equals(Date.class.getCanonicalName())) {
return DateSerializer.class.getCanonicalName();
} else if (typeName.equals(Boolean.class.getCanonicalName())) {
return BooleanSerializer.class.getCanonicalName();
}
// Build name avoiding generics collitions
StringBuilder implName = new StringBuilder();
makeImplName(pojoType, implName);
implName.append("_GuitJsonSerializer");
String packageName = pojoType.getPackage().getName();
if (packageName.startsWith("java.")) {
packageName = "com.guit.java." + packageName.substring(5);
}
String implNameString = implName.toString();
if (getClass(packageName, implNameString)) {
return packageName + "." + implNameString;
}
ClassSourceFileComposerFactory composer =
new ClassSourceFileComposerFactory(packageName, implNameString);
composer.addImplementedInterface(TypeJsonSerializer.class.getCanonicalName() + "<" + typeName
+ ">");
PrintWriter printWriter = context.tryCreate(logger, packageName, implNameString);
String createdName = composer.getCreatedClassName();
if (printWriter != null) {
SourceWriter writer = composer.createSourceWriter(context, printWriter);
JType iterableParameterType = null;
JPrimitiveType iterableParameterPrimitiveType = null;
// Iterable
JGenericType iterableType =
context.getTypeOracle().findType(Iterable.class.getCanonicalName()).isGenericType();
boolean isIterable = false;
if (iterableType.isAssignableFrom(pojoType)) {
isIterable = true;
iterableParameterType = pojoType.asParameterizationOf(iterableType).getTypeArgs()[0];
iterableParameterPrimitiveType = iterableParameterType.isPrimitive();
// Find if theres any exception
String qualifiedSourceName = pojoQualifiedName;
if (exceptions.containsKey(qualifiedSourceName)) {
parameterizedQualifiedSourceName =
exceptions.get(qualifiedSourceName) + "<"
+ iterableParameterType.getParameterizedQualifiedSourceName() + ">";
}
}
// Map
JGenericType mapType =
context.getTypeOracle().findType(Map.class.getCanonicalName()).isGenericType();
boolean isMap = false;
JClassType mapKeyType = null;
JClassType mapValueType = null;
if (mapType.isAssignableFrom(pojoType)) {
isMap = true;
JParameterizedType pojoMap = pojoType.asParameterizationOf(mapType);
JClassType[] args = pojoMap.getTypeArgs();
mapKeyType = args[0];
mapValueType = args[1];
// Find if theres any exception
String qualifiedSourceName = pojoQualifiedName;
if (exceptions.containsKey(qualifiedSourceName)) {
parameterizedQualifiedSourceName =
exceptions.get(qualifiedSourceName) + "<"
+ mapKeyType.getParameterizedQualifiedSourceName() + ","
+ mapValueType.getParameterizedQualifiedSourceName() + ">";
}
}
// Array
boolean isArray = false;
JArrayType pojoArray = pojoType.isArray();
if (pojoArray != null) {
isArray = true;
iterableParameterType = pojoArray.getComponentType();
iterableParameterPrimitiveType = iterableParameterType.isPrimitive();
}
// For pojos
ArrayList<JField> fields = null;
writer.println("public static " + createdName + " singleton;");
writer.println("public static " + createdName + " getSingleton() {");
writer.indent();
writer.println("return singleton == null ? (singleton = new " + createdName
+ "()) : singleton;");
writer.outdent();
writer.println("}");
writer.println("@Override");
writer.println("public " + JSONValue.class.getCanonicalName() + " serialize(" + typeName
+ " data) {");
writer.indent();
if (isMap) {
writer.println("if (data != null) {");
writer.indent();
writer.println(JSONArray.class.getCanonicalName() + " array = new "
+ JSONArray.class.getCanonicalName() + "();");
writer.println("int n = 0;");
writer.println("for (" + Entry.class.getCanonicalName() + "<"
+ mapKeyType.getParameterizedQualifiedSourceName() + ", "
+ mapValueType.getParameterizedQualifiedSourceName() + ">"
+ " entry : data.entrySet()) {");
writer.indent();
writer.print("array.set(n, ");
JPrimitiveType mapKeyPrimitive = mapKeyType.isPrimitive();
if (mapKeyPrimitive == null) {
printValueSerialized(logger, context, writer, "entry.getKey()", mapKeyType, pojoType);
} else {
printPrimitiveSerialized(typeName, writer, "entry.getKey()", mapKeyPrimitive);
}
writer.println(");");
writer.println("n++;");
writer.print("array.set(n, ");
JPrimitiveType mapValuePrimitive = mapValueType.isPrimitive();
if (mapValuePrimitive == null) {
printValueSerialized(logger, context, writer, "entry.getValue()", mapValueType, pojoType);
} else {
printPrimitiveSerialized(typeName, writer, "entry.getValue()", mapValuePrimitive);
}
writer.println(");");
writer.println("n++;");
writer.outdent();
writer.println("}");
writer.println("return array;");
writer.outdent();
writer.println("}");
writer.println("return " + JSONNull.class.getCanonicalName() + ".getInstance();");
} else if (isIterable || isArray) {
writer.println("if (data != null) {");
writer.indent();
writer.println(JSONArray.class.getCanonicalName() + " array = new "
+ JSONArray.class.getCanonicalName() + "();");
writer.println("int n = 0;");
writer.println("for (" + iterableParameterType.getParameterizedQualifiedSourceName()
+ " item : data) {");
writer.indent();
writer.print("array.set(n, ");
if (iterableParameterPrimitiveType == null) {
printValueSerialized(logger, context, writer, "item", iterableParameterType, pojoType);
} else {
printPrimitiveSerialized(typeName, writer, "item", iterableParameterPrimitiveType);
}
writer.println(");");
writer.println("n++;");
writer.outdent();
writer.println("}");
writer.println("return array;");
writer.outdent();
writer.println("}");
writer.println("return " + JSONNull.class.getCanonicalName() + ".getInstance();");
} else if (pojoType.isEnum() != null) {
writer.println("if (data != null) {");
writer.indent();
writer.println("return new " + JSONString.class.getCanonicalName() + "(data.name());");
writer.outdent();
writer.println("}");
writer.println("return " + JSONNull.class.getCanonicalName() + ".getInstance();");
} else {
// Assert the type have an empty constructor
try {
pojoType.getConstructor(emptyParameter);
} catch (NotFoundException e) {
error("The data type of the place does not have an empty constructor. Found %s", typeName);
}
writer.println(jsonObject + " json = new " + jsonObject + "();");
fields = new ArrayList<JField>();
getFields(fields, pojoType);
for (JField f : fields) {
String fieldName = f.getName();
String getterName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
JType fieldType = f.getType();
JPrimitiveType primitive = fieldType.isPrimitive();
String fieldTypeQualifiedType = fieldType.getQualifiedSourceName();
if (primitive != null) {
writer.print("json.put(\"" + fieldName + "\",");
printPrimitiveSerialized(typeName, writer, "get" + getterName + "(data)", primitive);
writer.println(");");
} else {
writer.println(fieldTypeQualifiedType + " " + fieldName + " = get" + getterName
+ "(data);");
writer.println("if (" + fieldName + " != null) {");
writer.indent();
writer.print("json.put(\"" + fieldName + "\",");
printValueSerialized(logger, context, writer, fieldName, fieldType, pojoType);
writer.println(");");
writer.outdent();
writer.println("}");
}
}
writer.println("return json;");
}
writer.outdent();
writer.println("}");
// Getters and setters
printJsniGettersAndSetters(writer, pojoType);
writer.println("@Override");
writer.println("public " + typeName + " deserialize(" + JSONValue.class.getCanonicalName()
+ " jsonValue) {");
writer.indent();
if (isMap) {
writer.println("if (jsonValue.isNull() == null) {");
writer.indent();
writer.println(JSONArray.class.getCanonicalName() + " jsonArray = jsonValue.isArray();");
writer.println("int jsonArraySize = jsonArray.size();");
writer.println(parameterizedQualifiedSourceName + " map = new "
+ parameterizedQualifiedSourceName + "();");
writer.println("for (int n = 0; n < jsonArraySize; n+=2) {");
writer.indent();
writer.println(JSONValue.class.getCanonicalName() + " key = jsonArray.get(n);");
writer.println(JSONValue.class.getCanonicalName() + " value = jsonArray.get(n + 1);");
writer.print("map.put(");
JPrimitiveType mapKeyPrimitive = mapKeyType.isPrimitive();
if (mapKeyPrimitive == null) {
printValueDeserialized(logger, context, writer, "key", mapKeyType);
} else {
printPrimitiveDeserialized(typeName, writer, "key", mapKeyPrimitive);
}
writer.print(",");
JPrimitiveType mapValuePrimitive = mapValueType.isPrimitive();
if (mapValuePrimitive == null) {
printValueDeserialized(logger, context, writer, "value", mapValueType);
} else {
printPrimitiveDeserialized(typeName, writer, "value", mapValuePrimitive);
}
writer.println(");");
writer.outdent();
writer.println("}");
writer.println("return map;");
writer.outdent();
writer.println("} else { return null; }");
} else if (isIterable || isArray) {
writer.println("if (jsonValue.isNull() == null) {");
writer.indent();
writer.println(JSONArray.class.getCanonicalName() + " jsonArray = jsonValue.isArray();");
writer.println("int jsonArraySize = jsonArray.size();");
if (isIterable) {
writer.println(parameterizedQualifiedSourceName + " array = new "
+ parameterizedQualifiedSourceName + "();");
} else {
JArrayType array = iterableParameterType.isArray();
if (array != null) {
String arrayName = array.getQualifiedSourceName() + "[]";
int index = arrayName.indexOf("[");
String arrayDeclaration =
arrayName.substring(0, index + 1) + "jsonArraySize"
+ arrayName.substring(index + 1);
writer.println(arrayName + " array = new " + arrayDeclaration + ";");
} else {
String parameterQualifiedName = iterableParameterType.getQualifiedSourceName();
writer.println(parameterQualifiedName + "[] array = new " + parameterQualifiedName
+ "[jsonArraySize];");
}
}
writer.println("for (int n = 0; n < jsonArraySize; n++) {");
writer.indent();
writer.println(JSONValue.class.getCanonicalName() + " item = jsonArray.get(n);");
if (isIterable) {
writer.print("array.add(");
} else {
writer.print("array[n] = ");
}
if (iterableParameterPrimitiveType == null) {
printValueDeserialized(logger, context, writer, "item", iterableParameterType);
} else {
printPrimitiveDeserialized(typeName, writer, "item", iterableParameterPrimitiveType);
}
if (isIterable) {
writer.println(");");
} else {
writer.println(";");
}
writer.outdent();
writer.println("}");
writer.println("return array;");
writer.outdent();
writer.println("} else { return null; }");
} else if (pojoType.isEnum() != null) {
writer.println("if (jsonValue.isNull() == null) {");
writer.indent();
writer.println("return " + typeName + ".valueOf(jsonValue.isString().stringValue());");
writer.outdent();
writer.println("} else { return null; }");
} else {
// Assert the type have an empty constructor
try {
pojoType.getConstructor(emptyParameter);
} catch (NotFoundException e) {
error("The data type of the place does not have an empty constructor. Found %s", typeName);
}
writer.println(JSONObject.class.getCanonicalName() + " json = jsonValue.isObject();");
writer.println(typeName + " instance = new " + typeName + "();");
for (JField f : fields) {
String fieldName = f.getName();
String setterName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
JType fieldType = f.getType();
JPrimitiveType primitive = fieldType.isPrimitive();
if (primitive != null) {
writer.print("set" + setterName + "(instance,");
printPrimitiveDeserialized(typeName, writer, "json.get(\"" + fieldName + "\")",
primitive);
writer.println(");");
} else {
writer.println("if (json.containsKey(\"" + fieldName + "\")) {");
writer.indent();
writer.print("set" + setterName + "(instance,");
printValueDeserialized(logger, context, writer, "json.get(\"" + fieldName + "\")",
fieldType);
writer.println(");");
writer.outdent();
writer.println("}");
}
}
writer.println("return instance;");
}
writer.outdent();
writer.println("}");
writer.commit(logger);
}
return createdName;
}
private static boolean getClass(String packageName, String implNameString) {
try {
Class.forName(packageName + "." + implNameString);
return true;
} catch (Exception e) {
return false;
}
}
private static void printJsniGettersAndSetters(SourceWriter writer, JClassType pojoType) {
for (JField f : pojoType.getFields()) {
// Non static, final or transient
if (f.isStatic() || f.isFinal() || f.isTransient()) {
continue;
}
String fieldName = f.getName();
String getterName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
JType fieldType = f.getType();
// Print getters and setters
String fieldTypeQualifiedType = fieldType.getQualifiedSourceName();
String pojoQualifiedName = pojoType.getQualifiedSourceName();
writer.println("private static native " + fieldTypeQualifiedType + " get" + getterName + "("
+ pojoQualifiedName + " instance) /*-{\n" + " return instance.@" + pojoQualifiedName
+ "::" + fieldName + ";\n" + " }-*/;\n" + " \n" + " private static native void set"
+ getterName + "(" + pojoQualifiedName + " instance, " + fieldTypeQualifiedType
+ " value) /*-{\n" + " instance.@" + pojoQualifiedName + "::" + fieldName
+ " = value;\n" + " }-*/;");
}
JClassType superclass = pojoType.getSuperclass();
if (superclass != null
&& !superclass.getQualifiedSourceName().equals(Object.class.getCanonicalName())) {
printJsniGettersAndSetters(writer, superclass);
}
}
private static void getFields(List<JField> fields, JClassType pojoType) {
for (JField f : pojoType.getFields()) {
// Non static, final or transient
if (f.isStatic() || f.isFinal() || f.isTransient()) {
continue;
}
fields.add(f);
}
JClassType superclass = pojoType.getSuperclass();
if (superclass != null
&& !superclass.getQualifiedSourceName().equals(Object.class.getCanonicalName())) {
getFields(fields, superclass);
}
}
private static void makeImplName(JType pojoType, StringBuilder implName) {
JArrayType array = pojoType.isArray();
if (pojoType.isPrimitive() != null) {
implName.append(pojoType.getSimpleSourceName());
} else if (array != null) {
implName.append("Array");
makeImplName(array.getComponentType(), implName);
} else {
JParameterizedType parameterized = pojoType.isParameterized();
implName.append(pojoType.getSimpleSourceName());
if (parameterized != null) {
JClassType[] args = parameterized.getTypeArgs();
for (JClassType a : args) {
makeImplName(a, implName);
}
}
}
}
private static void printPrimitiveDeserialized(String typeName, SourceWriter writer,
String fieldName, JPrimitiveType primitive) throws UnableToCompleteException {
if (primitive.equals(JPrimitiveType.BOOLEAN)) {
writer.println(fieldName + ".isBoolean().booleanValue()");
} else if (primitive.equals(JPrimitiveType.DOUBLE)) {
writer.println(fieldName + ".isNumber().doubleValue()");
} else if (primitive.equals(JPrimitiveType.FLOAT)) {
writer.println("(float)" + fieldName + ".isNumber().doubleValue()");
} else if (primitive.equals(JPrimitiveType.LONG)) {
writer.println("(long)" + fieldName + ".isNumber().doubleValue()");
} else if (primitive.equals(JPrimitiveType.INT)) {
writer.println("(int)" + fieldName + ".isNumber().doubleValue()");
} else {
error("The type %s is not a valid type for the place data. Found %s", primitive
.getSimpleSourceName(), typeName);
}
}
private static void printPrimitiveSerialized(String typeName, SourceWriter writer,
String fieldName, JPrimitiveType primitive) throws UnableToCompleteException {
if (primitive.equals(JPrimitiveType.BOOLEAN)) {
writer.print(JSONBoolean.class.getCanonicalName() + ".getInstance(" + fieldName + ")");
} else if (primitive.equals(JPrimitiveType.DOUBLE)) {
writer.print("new " + JSONNumber.class.getCanonicalName() + "(" + fieldName + ")");
} else if (primitive.equals(JPrimitiveType.FLOAT)) {
writer.print("new " + JSONNumber.class.getCanonicalName() + "(" + fieldName + ")");
} else if (primitive.equals(JPrimitiveType.LONG)) {
writer.print("new " + JSONNumber.class.getCanonicalName() + "(" + fieldName + ")");
} else if (primitive.equals(JPrimitiveType.INT)) {
writer.print("new " + JSONNumber.class.getCanonicalName() + "(" + fieldName + ")");
} else {
error("The type %s is not a valid type for the place data. Found %s", primitive
.getSimpleSourceName(), typeName);
}
}
private static void printValueDeserialized(TreeLogger logger, GeneratorContext context,
SourceWriter writer, String fieldName, JType fieldType) throws UnableToCompleteException {
String fieldTypeName = fieldType.getQualifiedSourceName();
if (fieldTypeName.equals(String.class.getCanonicalName())) {
writer.print(fieldName + ".isString().stringValue()");
} else if (fieldTypeName.equals(Integer.class.getCanonicalName())) {
writer.print("(int)" + fieldName + ".isNumber().doubleValue()");
} else if (fieldTypeName.equals(Long.class.getCanonicalName())) {
writer.print("(long)" + fieldName + ".isNumber().doubleValue()");
} else if (fieldTypeName.equals(Double.class.getCanonicalName())) {
writer.print(fieldName + ".isNumber().doubleValue()");
} else if (fieldTypeName.equals(Float.class.getCanonicalName())) {
writer.print("(float)" + fieldName + ".isNumber().doubleValue()");
} else if (fieldTypeName.equals(Date.class.getCanonicalName())) {
writer.print("new " + Date.class.getCanonicalName() + "((long)" + fieldName
+ ".isNumber().doubleValue())");
} else if (fieldTypeName.equals(Boolean.class.getCanonicalName())) {
writer.print(fieldName + ".isBoolean().booleanValue()");
} else {
JClassType classOrInterface = fieldType.isClassOrInterface();
writer.print(generate(logger, context, (classOrInterface != null ? classOrInterface
: fieldType.isArray()))
+ ".getSingleton().deserialize(" + fieldName + ")");
}
}
private static void printValueSerialized(TreeLogger logger, GeneratorContext context,
SourceWriter writer, String fieldName, JType fieldType, JClassType pojoType)
throws UnableToCompleteException {
String fieldTypeName = fieldType.getQualifiedSourceName();
if (fieldTypeName.equals(String.class.getCanonicalName())) {
writer.print("new " + JSONString.class.getCanonicalName() + "(" + fieldName + ")");
} else if (fieldTypeName.equals(Integer.class.getCanonicalName())) {
writer.print("new " + JSONNumber.class.getCanonicalName() + "(" + fieldName + ")");
} else if (fieldTypeName.equals(Long.class.getCanonicalName())) {
writer.print("new " + JSONNumber.class.getCanonicalName() + "(" + fieldName + ")");
} else if (fieldTypeName.equals(Double.class.getCanonicalName())) {
writer.print("new " + JSONNumber.class.getCanonicalName() + "(" + fieldName + ")");
} else if (fieldTypeName.equals(Float.class.getCanonicalName())) {
writer.print("new " + JSONNumber.class.getCanonicalName() + "(" + fieldName + ")");
} else if (fieldTypeName.equals(Date.class.getCanonicalName())) {
writer.print("new " + JSONNumber.class.getCanonicalName() + "(" + fieldName + ".getTime())");
} else if (fieldTypeName.equals(Boolean.class.getCanonicalName())) {
writer.print(JSONBoolean.class.getCanonicalName() + ".getInstance(" + fieldName + ")");
} else {
// We cannot serialize java.lang.Object
if (fieldType.getQualifiedSourceName().equals(Object.class.getCanonicalName())) {
error("You cannot serialize Object... we either. Found: %s.%s", pojoType
.getQualifiedSourceName(), fieldName);
}
JClassType classOrInterface = fieldType.isClassOrInterface();
writer.print(generate(logger, context, (classOrInterface != null ? classOrInterface
: fieldType.isArray()))
+ ".getSingleton().serialize(" + fieldName + ")");
}
}
}